/*
  LICENSE
  -------
Copyright 2005 Nullsoft, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer. 

  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution. 

  * Neither the name of Nullsoft nor the names of its contributors may be used to 
    endorse or promote products derived from this software without specific prior written permission. 
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/
#ifndef _MILKDROP_H_
#define _MILKDROP_H_ 1

#include <windows.h>
#include <ddraw.h>
#include <d3d.h>
#include <d3drm.h>

#include "state.h"
#include "sound.h"
#include "menu.h"
#include "yuv.h"
#include "texmgr.h"
#include "md_defines.h"


typedef enum { UI_REGULAR, UI_MENU, UI_PLAYLIST, UI_LOAD, UI_LOAD_DEL, UI_LOAD_RENAME, UI_SAVEAS, UI_SAVE_OVERWRITE, UI_EDIT_MENU_STRING, UI_CHANGEDIR } ui_mode;
typedef struct { float rad; float ang; } td_vertinfo;
typedef char* CHARPTR;
typedef char td_playlist_entry[128];

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

typedef struct
{
	bool	bActive;
	bool	bFilterBadChars;	// if true, it will filter out any characters that don't belong in a filename, plus the & symbol (because it doesn't display properly with DrawText)
	bool	bDisplayAsCode;		// if true, semicolons will be followed by a newline, for display
	int		nMaxLen;			// can't be more than 511
	int		nCursorPos;
	int		nSelAnchorPos;		// -1 if no selection made
	bool	bOvertypeMode;
	char	szText[8192];
	char	szPrompt[512];
	char	szToolTip[512];
	char	szClipboard[8192];
} td_waitstr;

typedef struct
{
	bool	bBold;
	bool	bItal;
	char	szFace[128];
	int		nColorR;    // 0..255
	int		nColorG;    // 0..255
	int		nColorB;    // 0..255
} 
td_custom_msg_font;

typedef struct
{
	int		nFont;
	float	fSize;	// 0..100
	float	x;
	float	y;
	float	randx;
	float   randy;
	float	growth;
	float	fTime;	// total time to display the message, in seconds
	float	fFade;	// % (0..1) of the time that is spent fading in
	
	// overrides
	bool    bOverrideBold;
	bool    bOverrideItal;
	bool    bOverrideFace;
	bool    bOverrideColorR;
	bool    bOverrideColorG;
	bool    bOverrideColorB;
	int		nColorR;    // 0..255
	int		nColorG;    // 0..255
	int		nColorB;    // 0..255
	int  	nRandR;
	int     nRandG;
	int  	nRandB;
	int     bBold;
	int     bItal;
	char    szFace[128];

	char	szText[256];
} 
td_custom_msg;

typedef struct
{
	bool	bRedrawSuperText;	// true if it needs redraw
	bool	bIsSongTitle;		// false for custom message, true for song title
	char	szText[256];
	char	nFontFace[128];
	bool	bBold;
	bool	bItal;
	float	fX;
	float   fY;
	float	fFontSize;			// [0..100] for custom messages, [0..4] for song titles
	float   fGrowth;			// applies to custom messages only
	int		nFontSizeUsed;		// height IN PIXELS
	float	fStartTime;
	float	fDuration;
	float	fFadeTime;			// applies to custom messages only; song title fade times are handled specially
	int  	nColorR;
	int     nColorG;
	int  	nColorB;
}
td_supertext;


class CMilkDropObj
{
public:
	CMilkDropObj();
	~CMilkDropObj();

	void		Init(HWND hWndParent, HINSTANCE hDllInstance);
	bool		GoFullScreen();
	void		RenderFrame(unsigned char *pL, unsigned char *pR);
	void		Finish();

	// GLOBAL DATA
	HWND		m_hMainWnd; // main window handle
	HWND		m_hWndParent;
	HINSTANCE	m_hDllInstance;

	HWND		m_hTextWnd;
	int			m_nTextWndWidth;
	int			m_nTextWndHeight;
	bool		m_bSeparateTextWindow;
	bool		m_bTextWindowClassRegistered;
	HDC			m_memDC;		// memory device context
	HBITMAP		m_memBM, m_oldBM;
	HBRUSH		m_hBlackBrush;

	bool		m_bInitComplete;
	bool		m_bExiting;
	bool		m_bWinampMinimized;
	bool		m_bWindowClassRegistered;
	bool		m_bMMX;
	//bool		m_bSSE;
	bool		m_bDesktopMode;
	bool		 m_bLostFocus;
	bool		 m_bSystrayReady;
	int			 m_nDesktopProcSize;		// 0=full, 1=half, 2=quarter
	char		 m_szOldWallpaper[512];
	DWORD		 m_dwOldBackgroundColor;
	bool		 m_bOldWallpaperKnown;
	bool		 m_bWallpaperSet;
	int			 m_key_R;	
	int			 m_key_G;	
	int			 m_key_B;	
	bool		 m_bHardwareDesktopBlit;
	//bool		 m_bDesktopModeSkipBurstCopy;
	bool		 m_bTryRGBOverlayFirst;
	bool		 m_bTryYUY2OverlayFirst;
	bool		 m_bDesktopModeDoubleBuffered;
	int          m_xBusMode[2];
	bool		m_bWindowed;
	bool		 m_bSizingWindow;
	bool		m_bOrigScrollLockState;

	// config panel options:
	bool		m_bFirstRun;
	float		m_fBlendTimeAuto;		// blend time when preset auto-switches
	float		m_fBlendTimeUser;		// blend time when user loads a new preset
	float		m_fTimeBetweenPresets;		// <- this is in addition to m_fBlendTimeAuto
	float		m_fTimeBetweenPresetsRand;	// <- this is in addition to m_fTimeBetweenPresets
	bool        m_bSequentialPresetOrder;
	bool		m_bHardCutsDisabled;
	float		m_fHardCutLoudnessThresh;
	float		m_fHardCutHalflife;
	float		m_fHardCutThresh;
	int			m_nWidth;
	int			m_nHeight;
	int			m_nDispBits;
	int			m_nTexSize;
	int			m_nGridX;
	int			m_nGridY;

	char		m_szFontFace[NUM_FONTS][128];
	int			m_nFontSize[NUM_FONTS];
	bool		m_bFontBold[NUM_FONTS];
	bool		m_bFontItalic[NUM_FONTS];
	char		 m_szTitleFontFace[128];
	int			 m_nTitleFontSize;			// percentage of screen width (0..100)
	bool		 m_bTitleFontBold;
	bool		 m_bTitleFontItalic;

	int         m_nNumericInputMode;	// NUMERIC_INPUT_MODE_CUST_MSG, NUMERIC_INPUT_MODE_SPRITE
	int         m_nNumericInputNum;
	int			m_nNumericInputDigits;
	td_custom_msg_font   m_CustomMessageFont[MAX_CUSTOM_MESSAGE_FONTS];
	td_custom_msg        m_CustomMessage[MAX_CUSTOM_MESSAGES];

	texmgr      m_texmgr;		// for user sprites

	td_supertext m_supertext;	// **contains info about current Song Title or Custom Message.**

	bool		m_bShowPressF1ForHelp;
	char		m_szMonitorName[256];
	bool		m_bShowMenuToolTips;
	int			m_n16BitGamma;
	bool		m_bAutoGamma;
	int			m_nFpsLimit;
	int			m_cLeftEye3DColor[3];
	int			m_cRightEye3DColor[3];
	bool		m_bEnableRating;
	bool		m_bSongTitleAnims;
	float		m_fTimeBetweenRandomSongTitles;
	float		m_fTimeBetweenRandomCustomMsgs;
	int			m_nSongTitlesSpawned;
	int			m_nCustMsgsSpawned;

	float		m_fSongTitleAnimDuration;
	bool		m_bClearScreenAtStartup;
	bool		m_bAlways3D;
	bool		m_bFixSlowText;
	bool		m_bAlwaysOnTop;
	bool		m_bWarningsDisabled;		// messageboxes
	bool		m_bWarningsDisabled2;		// warnings/errors in upper-right corner (m_szUserMessage)

	// temporary runtime data
	bool		m_bTexSizeWasAuto;
	bool		m_bPresetLockedByUser;
	bool		m_bPresetLockedByCode;
	int			m_nFrames;
	float		m_fAnimTime;
	float		m_fStartTime;
	float		m_fPresetStartTime;
	float		m_fNextPresetTime;
	float		m_fTimeHistory[64];		// for computing fps
	int			m_nTimeHistoryPos;		// for computing fps
	float		m_fps;
	float		m_fFPSLimitSleep;
	CState		*m_pState;				// points to current CState
	CState		*m_pOldState;			// points to previous CState
	CState		m_state_DO_NOT_USE[2];	// do not use; use pState and pOldState instead.
	ui_mode		m_UI_mode;				// can be UI_REGULAR, UI_LOAD, UI_SAVEHOW, or UI_SAVEAS 
	td_playlist_entry *m_szPlaylist;	// array of 128-char strings
	int			m_nPlaylistCurPos;
	int			m_nPlaylistLength;
	int			m_nTrackPlaying;
	int			m_nSongPosMS;
	int			m_nSongLenMS;
	bool		m_bUserPagedUp;
	bool		m_bUserPagedDown;
	float		m_fMotionVectorsTempDx;
	float		m_fMotionVectorsTempDy;

	td_waitstr  m_waitstring;
	void		WaitString_NukeSelection();
	void		WaitString_Cut();
	void		WaitString_Copy();
	void		WaitString_Paste();
	void		WaitString_SeekLeftWord();
	void		WaitString_SeekRightWord();
	int			WaitString_GetCursorColumn();
	int			WaitString_GetLineLength();
	void		WaitString_SeekUpOneLine();
	void		WaitString_SeekDownOneLine();

	int			m_nPresets;			// the # of entries in the file listing.  Includes directories and then files, sorted alphabetically.
	int			m_nDirs;			// the # of presets that are actually directories.  Always between 0 and m_nPresets.
	int			m_nPresetListCurPos;// Index (in m_pPresetAddr[]) of the currently-HIGHLIGHTED preset (the user must press Enter on it to select it).
	int			m_nCurrentPreset;	// Index (in m_pPresetAddr[]) of the currently-RUNNING preset.  
									//   Note that this is NOT the same as the currently-highlighted preset! (that's m_nPresetListCurPos)
									//   Be careful - this can be -1 if the user changed dir. & a new preset hasn't been loaded yet.
	char		m_szCurrentPresetFile[512];	// this is always valid (unless no presets were found)
	CHARPTR		*m_pPresetAddr;		// slot n of this array is a pointer to the nth string in m_szpresets.  (optimization; allows for constant-time access.)  Each entry is just a filename + extension (with no path - the path is m_szPresetDir for all of them).
	float		*m_pfPresetRating;				// not-cumulative version
	char        *m_szpresets;		// 1 giant dynamically-allocated string; actually a string-of-strings, containing 'm_nPresets' null-terminated strings one after another; and the last string is followed with two NULL characters instead of just one.  
	int			m_nSizeOfPresetList; // the # of bytes currently allocated for 'm_szpresets'

	// stuff for displaying text to user:
	int			m_nTextHeightPixels;	// this is for the menu/detail font; NOT the "fancy font"
	int			m_nTextHeightPixels_Fancy;
	bool		m_bShowFPS;
	bool		m_bShowRating;
	bool		m_bShowPresetInfo;
	bool		m_bShowDebugInfo;
	bool		m_bShowSongTitle;
	bool		m_bShowSongTime;
	bool		m_bShowSongLen;
	bool		m_bShowHelpInfo;
	float		m_fShowUserMessageUntilThisTime;
	float		m_fShowRatingUntilThisTime;
	char		m_szUserMessage[512];
	char		m_szDebugMessage[512];
	char		m_szSongMessage[512];
	char		m_szSongTime[512];
	HFONT		m_hfont[3];	// 0=fancy font (for song titles, preset name)
							// 1=legible font (the main font)
							// 2=tooltip font (for tooltips in the menu system)
	//HFONT       m_htitlefont[NUM_TITLE_FONTS]; // ~25 different sizes
	// stuff for menu system:
	CMilkMenu	*m_pCurMenu;	// should always be valid!
	CMilkMenu	 m_menuPreset;
	CMilkMenu	  m_menuWave;
	CMilkMenu	  m_menuAugment;
	CMilkMenu	  m_menuMotion;
	CMilkMenu	  m_menuPost;
	CMilkMenu	 m_menuSettings;

	// SOUND DATA & ANALYSIS
	CSoundData  sound;

	// GLOBAL FUNCTIONS
	void		WriteConfig();	// called only when OK clicked on config panel
	void		WriteRealtimeConfig();	// called on Finish()
	void		dumpmsg(char *s);
	void		Randomize();
	void		LoadRandomPreset(float fBlendTime);
	void		LoadPreset(char *szPresetFilename, float fBlendTime);
	void		UpdatePresetList();
	void		UpdatePresetRatings();
	char*		GetConfigIniFile() { return m_szConfigIniFile; };
	char*		GetMsgIniFile()    { return m_szMsgIniFile; };
	char*		GetPresetDir()     { return m_szPresetDir; };
	void		SavePresetAs(char *szNewFile);		// overwrites the file if it was already there.
	void		DeletePresetFile(char *szDelFile);	
	void		RenamePresetFile(char *szOldFile, char *szNewFile);
	void		SetCurrentPresetRating(float fNewRating);
	void		SeekToPreset(char cStartChar);
	bool		ReversePropagatePoint(float fx, float fy, float *fx2, float *fy2);
	void		HandleRegularKey(WPARAM wParam);
	bool		OnResizeGraphicsWindow();
	bool		OnResizeTextWindow();
	bool		InitFont();
	void		ToggleControlWindow();	// for Desktop Mode only
	void		DrawUI();
	void		ClearGraphicsWindow();	// for windowed mode only
    bool        Update_Overlay();
	void		UpdatePlaylist();
	void		LaunchCustomMessage(int nMsgNum);
	void		ReadCustomMessages();
	void		LaunchSongTitleAnim();

	// MULTIPLE MONITORS
	GUID					m_guidMonitor;
	bool					m_bMonitorFound;

	// SEMAPHORES
	CRITICAL_SECTION		m_cs;

protected:

	//data
	char		m_szWinampPluginsPath[MAX_PATH];		// ends in a backslash
	char		m_szConfigIniFile[MAX_PATH];
	char		m_szMsgIniFile[MAX_PATH];
	char        m_szImgIniFile[MAX_PATH];
	char		m_szPresetDir[MAX_PATH];
	bool		m_bDisplayModeChanged;
	DWORD		m_dwStartTickCount;
	DWORD		m_dwPrevTickCount;
	float		m_fRandStart[4];

	// DDRAW
	LPDIRECTDRAW7			m_lpDD;           // DirectDraw object
	LPDIRECTDRAWSURFACE7    m_lpDDSPrimary;   
	LPDIRECTDRAWSURFACE7    m_lpDDSBack;      
	LPDIRECTDRAWSURFACE7    m_lpVS[2];
	LPDIRECTDRAWSURFACE7    m_lpDDSOverlay;	// for overlay (desktop) mode
	LPDIRECTDRAWSURFACE7    m_lpDDSOverlayBack;	// for overlay (desktop) mode
	LPDIRECTDRAWSURFACE7    m_lpSysMemBack[2];
	LPDIRECTDRAWSURFACE7    m_lpDDSTitle[2];
	LPDIRECTDRAWSURFACE7    m_lpDDSText;
	int						m_nTitleTexSizeX, m_nTitleTexSizeY;
	//LPDIRECTDRAWSURFACE7    m_lpSprite[8];
	DDCAPS					m_ddcaps;

	// D3D
	LPDIRECT3D7				m_pD3D;				
	LPDIRECT3DDEVICE7		m_lpD3DDev;			
	D3DDEVICEDESC7			m_D3DDevDesc;
	D3DLVERTEX				*m_verts;
	D3DLVERTEX				*m_verts_temp;
	td_vertinfo				*m_vertinfo;
	WORD					*m_indices;

	RECT					m_clientRect;				// for windowed mode

	// OVERLAY (DESKTOP) MODE
    fourcc_enum             m_eOverlayFormat;
	int						m_nDesktopWidth;
	int						m_nDesktopHeight;
	DDCOLORKEY              m_ddck;
	void*					m_pDesktopModeScratchBits1_aligned;	// ..to an 8-byte boundary
	void*					m_pDesktopModeScratchBits1_orig;
	bool					 TryCreateOverlayRGB(DDSURFACEDESC2 *pddsd);
    void                     Destroy_Overlay();
    bool                     Init_Overlay(bool bShowMsgBoxes);
	void					 RestoreWallpaper();
	void					 SetWallpaper();
	bool					SetMilkdropRenderTarget(LPDIRECTDRAWSURFACE7 lpSurf, int w, int h, char *szErrorMsg);

	//methods
	void		ReadConfig();
	bool		CreateTheWindow();	// called by GoFullScreen
	bool		InitDDraw();		// called by GoFullScreen
	bool		InitD3D();			// called by GoFullScreen
	bool		RenderStringToTitleTexture();
	void		ShowSongTitleAnim(LPDIRECTDRAWSURFACE7 lpRenderTarget, int w, int h, float fProgress);
	//void		IdentifyD3DError(HRESULT hr);
	void		UpdateSongInfo();
	void		UpdateTime();
	void		DrawWave(float *fL, float *fR);
	void		DrawSprites();
	void		WarpedBlitFromVS0ToVS1();
	void		RunPerFrameEquations();
	void		ShowToUser();
	void		DrawUserSprites();
	void		MergeSortPresets(int left, int right);
	void		BuildMenus();
	void		ResetWindowSizeOnDisk();
	bool		LaunchSprite(int nSpriteNum, int nSlot);
	void		KillSprite(int iSlot);
};































#endif